import { Alert, CodeGroup, ContentByFramework } from "@/components/forMdx";

export const metadata = {
  description: "Learn how to use branching and merging in Jazz"
};

# Version Control

Jazz provides built-in version control through branching and merging, allowing multiple users to work on the same resource in isolation and merge their changes when they are ready.

This enables the design of new editing workflows where users (or agents!) can create branches, make changes, and merge them back to the main version.

<Alert variant="info" className="mt-4 flex gap-2 items-center">
  <strong>Important:</strong> Version control is currently unstable and we may ship breaking changes in patch releases.
</Alert>

## Working with branches

### Creating Branches

To create a branch, use the `unstable_branch` option when loading a CoValue:

<CodeGroup>
```ts index.ts#Branch
```
</CodeGroup>

<ContentByFramework framework={["react", "react-native", "expo"]}>
You can also create a branch via the `useCoState` hook:

<CodeGroup>
```ts react-snippet.tsx#UseCoState
```
</CodeGroup>
</ContentByFramework>
<ContentByFramework framework={["svelte"]}>
You can also create a branch via `CoState`:

<CodeGroup>
```ts svelte.svelte#CoState
```
</CodeGroup>
</ContentByFramework>

You can also include nested CoValues in your branch by using a [`resolve` query](/docs/core-concepts/subscription-and-loading#resolve-queries).

You are in control of how nested CoValues are included in your branch. When you specify the CoValue to branch, any nested CoValues specified in a `resolve` query will also be branched. Nested CoValues *not* specified in your resolve query will not be branched.

In order to access branched nested CoValues, you should access them in the same way you would normally access a deeply loaded property, and all operations will work within the branch context.

<Alert variant="info" className="mt-4 flex gap-2 items-center">
  In case you create a separate reference to a nested CoValue (for example by loading it by its ID), or you use `.$jazz.ensureLoaded()` or `.$jazz.subscribe()`, you will need to specify the branch you wish to load.
</Alert>

### Making Changes

Once you have a branch, you can make changes just as you would with the original CoValue:

{/* TODO: this is not suitable for vanilla */}
<ContentByFramework framework={["react", "react-native", "expo", "vanilla"]}>
<CodeGroup>
```tsx react-snippet.tsx#EditOnBranch
```
</CodeGroup>
</ContentByFramework>
<ContentByFramework framework={["svelte"]}>
<CodeGroup>
```svelte EditOnBranch.svelte
```
</CodeGroup>
</ContentByFramework>

### Account & Group

Branching does not bring isolation on Account and Group CoValues.

This means that, adding a member on a branched Group will also add the member to the main Group.

<CodeGroup>
```ts index.ts#Permissions
```
</CodeGroup>

If you are modifying an account, be aware that replacing the root or profile  will also modify the main account (although updating the properties will happen on the branch).

{/* TODO: Not framework friendly */}
<CodeGroup>
```tsx react-snippet.tsx#AccountModifications
```
</CodeGroup>

### Merging Branches

There are two ways to merge a branch in Jazz, each with different characteristics:

#### 1. Merge loaded values

This method merges all the values that are currently loaded inside the branch. It happens synchronously and there is no possibility of errors because the values are already loaded.

<CodeGroup>
```ts index.ts#Merge
```
</CodeGroup>

This approach is recommended when you can co-locate the merge operation with the branch load, keeping at a glance what the merge operation will affect.

<Alert variant="info" className="mt-4 flex gap-2 items-center">
  <strong>Important:</strong> The merge operation will only affect values loaded in the current subscription scope. Values loaded via `ensureLoaded` or `subscribe` will not be affected.
</Alert>

#### 2. Merge with resolve query

This is a shortcut for loading a value and calling `branch.$jazz.unstable_merge()` on it and will fail if the load isn't possible due to permission errors or network issues.

<CodeGroup>
```ts index.ts#MergeWithResolve
```
</CodeGroup>

This approach is recommended for more complex merge operations where it's not possible to co-locate the merge with the branch load.

#### Best Practices

When using version control with Jazz, always be exhaustive when defining the resolve query to keep the depth of the branch under control and ensure that the merge covers all the branched values.

The mechanism that Jazz uses to automatically load accessed values should be avoided with branching, as it might lead to cases where merge won't reach all the branch changes.

All the changes made to the branch will be merged into the main CoValue, preserving both author and timestamp.

The merge is idempotent, so you can merge the same branch multiple times, the result will always depend on the branch changes and loading state.

The merge operation cascades down to the CoValue's children, but not to its parents. So if you call `unstable_merge()` on a task, only the changes to the task and their children will be merged:

<CodeGroup>
```tsx index.ts#CascadingMerge
```
</CodeGroup>


## Conflict Resolution

When conflicts occur (the same field is modified in both the branch and main), Jazz uses a "last writer wins" strategy:

<CodeGroup>
```ts index.ts#ConflictResolution
```
</CodeGroup>

## Private branches

When the owner is not specified, the branch has the same permissions as the main values.

You can also create a private branch by providing a group owner.

<CodeGroup>
```ts index.ts#PrivateBranches
```
</CodeGroup>

You can use private branches both to make the changes to the branches "private" until merged, or to give controlled write access to a group of users.

Only users with both write access to the main branch and read access to the private branch have the rights to merge the branch.

<Alert variant="info" className="mt-4 flex gap-2 items-center">
  <strong>Important:</strong> Branch names are scoped to their owner. The same branch name with different owners creates completely separate branches. For example, a branch named "feature-branch" owned by User A is completely different from a branch named "feature-branch" owned by User B.
</Alert>

## Branch Identification

You can get the current branch information from the `$jazz` field.

<CodeGroup>
```ts index.ts#BranchIdentification
```
</CodeGroup>
